/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.diagram.composite.figure;

import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.FigureUtilities;
import org.eclipse.draw2d.FreeformLayer;
import org.eclipse.draw2d.FreeformLayout;
import org.eclipse.draw2d.FreeformViewport;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.LineBorder;
import org.eclipse.draw2d.ScrollPane;
import org.eclipse.draw2d.StackLayout;
import org.eclipse.draw2d.ToolbarLayout;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.uml2.uml.Element;

import com.cea.papyrus.core.PapyrusPlugin;
import com.cea.papyrus.core.figures.NodeFigure;
import com.cea.papyrus.core.utils.Debug;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;

/**
 * Figure of the Class drawn in a composite diagram.
 */
public class ClassFigure extends NodeFigure {

	/** Debug channel */
	private final static int debugChannel=6;

	/** table used to drawn dashes, when the class is extern for example */
	protected int [] dashes= new int[10];

	/** boolean that indicates if the class is extern */
	protected boolean extern= false;
	
	/** boolean that indicates if the class is a container */
	protected boolean isContainer=true;
	
	/** boolean that indicates if the class name must be underlined */	
	protected boolean isNameUnderlined=false;

	/** background color for the class */
	public static Color classColor = PapyrusPlugin.colorManager.get(new RGB(227,221,239));

	/** border color for the class */
	public static Color classBorderColor= PapyrusPlugin.colorManager.get(new RGB(166,157,183));

	/** Figure that displays the name of the class */
	protected UMLClassHeaderFigure headerFigure;

	/** Figure that contains elements owned by the class, like properties */
	protected UMLClassContentFigure contentFigure = null;

	/**
	 * Figure that represents the header of a class, 
	 * drawn in a Composite diagram. the header displays 
	 * information like the class name, etc.
	 */
	class UMLClassHeaderFigure extends NodeFigure {
		
		/**
		 * Creates a new UMLClassHeaderFigure
		 */
		public UMLClassHeaderFigure() {
			ToolbarLayout layout = new ToolbarLayout();

			setLayoutManager(layout);
			layout.setSpacing(2);
			setOpaque(true); // non-transparent figure
			setBorder( new LineBorder(ColorConstants.black));
			setBackgroundColor(ColorConstants.yellow);	

		}

		/* (non-Javadoc)
		 * @see org.eclipse.draw2d.Figure#setBounds(org.eclipse.draw2d.geometry.Rectangle)
		 */
		@Override
		public void setBounds(Rectangle rect) {

			int headerHeight = getNameLabel().getPreferredSize().height+10;
			int headerWidth  = rect.width;

			// Calculate height
			if (getStereotypesLabel() != null) {
				headerHeight = headerHeight +getStereotypesLabel().getPreferredSize().height+5;
			}
			if (getIconLabel() != null) {
				headerHeight = headerHeight + getIconLabel().getPreferredSize().height;
			}
			if (getQualifiedNameLabel() != null) {
				headerHeight = headerHeight + getQualifiedNameLabel().getPreferredSize().height+5;
			}
			Rectangle headerRect = new Rectangle();
			headerRect.setLocation(0, 0);
			headerRect.setSize(headerWidth, headerHeight);

			super.setBounds(headerRect);

			Debug.debug(this," bounds are : " +getBounds(), debugChannel);
		}

	}

	/**
	 * Figure that represents the content of a class, 
	 * drawn in a Composite diagram
	 */
	class UMLClassContentFigure extends NodeFigure  {

		/** Figure that represents the inner pane*/
		private IFigure pane;

		/**
		 * Creates a new UMLClassContentFigure
		 */
		public UMLClassContentFigure() {
			Debug.debug(this,"  Call UMLPackageContentFigure", debugChannel);

			// Set content layout
			setLayoutManager(new StackLayout());

			// Add pane for content
			pane = new FreeformLayer();
			pane.setLayoutManager(new FreeformLayout());

			// Add scrollpane
			ScrollPane scrollpane = new ScrollPane();
			scrollpane.setViewport(new FreeformViewport());
			scrollpane.setContents(pane);
			this.add(pane);

			// Set colors
			setBackgroundColor(headerFigure.getBackgroundColor());
			setBorder(new LineBorder(headerFigure.getBorderColor()));
			setOpaque(true);
		}

		/**
		 * Returns the inner content pane figure
		 * @return the inner content pane figure
		 */
		public IFigure getContentPane() {
			return pane;
		}

		/* (non-Javadoc)
		 * @see org.eclipse.draw2d.Figure#setBounds(org.eclipse.draw2d.geometry.Rectangle)
		 */
		@Override
		public void setBounds(Rectangle rect) {

			// Father dimension
			int fatherHeight = getParent().getBounds().height;
			int fatherWidth  = getParent().getBounds().width;

			super.setBounds(new Rectangle(
					0
					, headerFigure.getSize().height-1
					, fatherWidth
					, fatherHeight-headerFigure.getSize().height));

			Debug.debug(this," bounds are : " +getBounds(), debugChannel);
		}
	}

	/**
	 * Creates a new ClassFigure.
	 */
	public ClassFigure() {
		ToolbarLayout layout = new ToolbarLayout();
		setLayoutManager(layout);
		for (int i=0;i<10;i++) {
			dashes[i]=5;
		}

		headerFigure = new UMLClassHeaderFigure();
		add(headerFigure);
		contentFigure =new UMLClassContentFigure();
		add(contentFigure);	
		super.setBorder(null);
		setOpaque(false);
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.figures.NodeFigure#setBorderColor(org.eclipse.swt.graphics.Color)
	 */
	@Override
	public void setBorderColor(Color borderColor) {
		this.borderColor = borderColor;
		getHeader().setBorder(null);
		contentFigure.setBorder(null);
	}

	/* (non-Javadoc)
	 * @see org.eclipse.draw2d.Figure#paintBorder(org.eclipse.draw2d.Graphics)
	 */
	@Override
	public void paintBorder(Graphics graphics) {
		graphics.setForegroundColor(getBorderColor());
		if( extern){	
			graphics.setLineDash(dashes);
		}
		graphics.setLineWidth(1);

		graphics.drawRectangle(this.getBounds().x,
				this.getBounds().y,
				this.getBounds().width-1,
				this.getBounds().height-1);
		//draw line separator
		Rectangle rect = getHeader().getBounds();
		if( isContainer){
			graphics.drawLine(this.getBounds().x,
					this.getBounds().y+this.getHeadHeight(),
					this.getBounds().x+this.getBounds().width-1,
					this.getBounds().y+this.getHeadHeight());
		}

		if (isNameUnderlined) {
			graphics.setForegroundColor(ColorConstants.black);
			Rectangle rectLabel = getNameLabel().getBounds();
			Dimension labelSize=FigureUtilities.getTextExtents(getNameLabel().getText(), getNameLabel().getFont());
			graphics.drawLine(this.getBounds().x+rectLabel.width/2-labelSize.width/2,
					this.getBounds().y+rectLabel.height-2,
					this.getBounds().x+rectLabel.width/2+labelSize.width/2,
					this.getBounds().y+rectLabel.height-2);
		}
	}

	/**
	 * Display dashes is the composite is extern.
	 * @param value <code>true</code> if the class is extern and that the figure has to be 
	 * drawn with dashes
	 */
	public void setExtern(boolean value){
		this.extern =value;
		this.repaint();
	}

	/**
	 * Sets if the name has to be underlined or not
	 * @param isNameUnderlined <code>true</code> if the name has to be underlined
	 */
	public void setNameUnderlined(boolean isNameUnderlined) {
		this.isNameUnderlined = isNameUnderlined;
		this.repaint();
	}

	/**
	 * Set the container value to the specified boolean. 
	 * @param value <code>true</code> if the figure is a container
	 */ 
	public void setContainer(boolean value){
		this.isContainer = value;
		this.repaint();
	}
	
	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.figures.NodeFigure#setBackgroundColor(org.eclipse.swt.graphics.Color)
	 */
	@Override
	public void setBackgroundColor(Color backgroundColor) {
		// sets the background color for both sub-figures
		super.setBackgroundColor(backgroundColor);
		headerFigure.setBackgroundColor(backgroundColor);
		contentFigure.setBackgroundColor(backgroundColor);
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.figures.NodeFigure#setFontColor(org.eclipse.swt.graphics.Color)
	 */
	@Override
	public void setFontColor(Color color) {
		this.fontColor=color;
		getHeader().setFontColor(color);
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.figures.NodeFigure#setForeGroundColor(org.eclipse.swt.graphics.Color)
	 */
	@Override
	public void setForeGroundColor(Color color) {
		super.setForeGroundColor(color);

	}

	/* (non-Javadoc)
	 * @see org.eclipse.draw2d.Figure#setBounds(org.eclipse.draw2d.geometry.Rectangle)
	 */
	@Override
	public void setBounds(Rectangle rect) {
		// calls set bound for each sub-figure

		// Header
		headerFigure.setBounds(new Rectangle(rect));
		// Content
		contentFigure.setBounds(new Rectangle(rect));

		super.setBounds(new Rectangle(rect));

		Debug.debug(this," bounds are : " +getBounds(), debugChannel);
	}

	/**
	 * Returns the header of the figure, where name and other information are displayed
	 * @return the header of the figure
	 */
	public UMLClassHeaderFigure getHeader() {
		return headerFigure;
	}

	/**
	 * Returns the content pane of this figure, e.g. where elements have to be added
	 * @return the content pane of this figure
	 */
	public IFigure getContentsPane(){
		return contentFigure.getContentPane();
	}

	/* (non-Javadoc)
	 * @see org.eclipse.draw2d.Figure#useLocalCoordinates()
	 */
	@Override
	protected boolean useLocalCoordinates(){
		return true;
	}

	/**
	 * Returns the width of the header figure
	 * @return the width of the header figure
	 */
	public int getHeadWitdh(){
		return headerFigure.getPreferredSize().width;
	}

	/**
	 * Returns the height of the header figure
	 * @return the height of the header figure
	 */
	public int getHeadHeight(){ 
		return headerFigure.getPreferredSize().height;
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.figures.NodeFigure#getNameLabel()
	 */
	@Override
	public Label getNameLabel() {
		return headerFigure.getNameLabel();
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.figures.NodeFigure#getQualifiedNameLabel()
	 */
	@Override
	public Label getQualifiedNameLabel() {
		return headerFigure.getQualifiedNameLabel();
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.figures.NodeFigure#getStereotypesLabel()
	 */
	@Override
	public Label getStereotypesLabel() {
		return headerFigure.getStereotypesLabel();
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.figures.NodeFigure#setName(java.lang.String)
	 */
	@Override
	public void setName( String name ) {
		headerFigure.setName(name);
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.figures.NodeFigure#setQualifiedName(java.lang.String)
	 */
	@Override
	public void setQualifiedName( String packageName ) {
		headerFigure.setQualifiedName(packageName);
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.figures.NodeFigure#setStereotypes(java.lang.String)
	 */
	@Override
	public void setStereotypes( String stereotypes ) {
		headerFigure.setStereotypes(stereotypes);
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.figures.NodeFigure#refreshPresentation(java.lang.String, org.eclipse.uml2.uml.Element)
	 */
	@Override
	public void refreshPresentation(String presentation, Element selection, GraphElement ge) {
		headerFigure.refreshPresentation(presentation, selection, ge);
	}

	/* (non-Javadoc)
	 * @see com.cea.papyrus.core.common.figures.NodeFigure#refreshStereotypes(java.lang.String, java.lang.String, boolean, boolean)
	 */
	@Override
	public void refreshStereotypes(String stereotypes, String presentation, boolean hasIcon, boolean hasShape) {
		headerFigure.refreshStereotypes(stereotypes, presentation, hasIcon, hasShape);
	}

	/**
	 * Sets the font for the name label, depending on the specified boolean.
	 * if b is <code>true</code>, name is written in italic (class is abstract)
	 * @param b <code>true</code> if the name has to be written in italic
	 */
	public void setAbstract(boolean b) {
		if (b) {
			FontData[] font={new FontData(getfigureFont(), getFontSize(), SWT.ITALIC|SWT.BOLD)};
			this.getNameLabel().setFont(PapyrusPlugin.fontManager.get(font));//italic
		} else {
			FontData[] font={new FontData(getfigureFont(), getFontSize(), SWT.BOLD)};
			this.getNameLabel().setFont( PapyrusPlugin.fontManager.get(font));
		}
	}


}
